/*
 * MainGameController.cpp
 *
 *  Created on: Dec 27, 2011
 *      Author: rudi
 */
#include <wx/socket.h>
#include "MainGameController.h"
#include "IdleGameStateController.h"
#include "ServerStartingGameStateController.h"
#include "ClientStartingGameStateController.h"
#include "GameStartedGameStateController.h"
#include "GameFinishedGameStateController.h"
#include "App.h"
#include "MainFrame.h"
#include "MainPanel.h"

BEGIN_EVENT_TABLE(MainGameController, wxEvtHandler)
  EVT_SOCKET(wxID_ANY, MainGameController::handleSocketEvent)
END_EVENT_TABLE()

/**
 * MainGameController::ChangeStateTask class
 */

MainGameController::ChangeStateTask::ChangeStateTask(MainGameController* mainGameController,
													 SmartPointer<IGameStateController> gameStateController): mMainGameController(mainGameController),
																											 mGameStateController(gameStateController)
{
	// Nothing to do yet
}

/*virtual*/
MainGameController::ChangeStateTask::~ChangeStateTask()
{
	// Nothing to do yet
}

void MainGameController::ChangeStateTask::execute()
{
	mMainGameController->mGameStateController = mGameStateController;
	// Force a refresh
	wxGetApp().getMainFrame()->getMainPanel()->Refresh();
}

/**
 * MainGameController class
 */

MainGameController::MainGameController(MainPanel* mainPanel)
{
	// The initial state is the Idle state
	mGameStateController = new IdleGameStateController(mainPanel);
}

/*virtual*/
MainGameController::~MainGameController()
{
	// Nothing to do yet
}
//
// Methods inherited from Controller
//

void MainGameController::handleMouseDown(const wxPoint& position)
{
	mGameStateController->handleMouseDown(position);
}

void MainGameController::handleMouseUp(const wxPoint& position)
{
	mGameStateController->handleMouseUp(position);
}

bool MainGameController::handleMouseMotion(const wxPoint& position)
{
	return mGameStateController->handleMouseMotion(position);
}

const wxBitmap& MainGameController::getBitmapToPaint() const
{
	return mGameStateController->getBitmapToPaint();
}

wxBitmap& MainGameController::getBitmapToDraw()
{
	return mGameStateController->getBitmapToDraw();
}

//
// Methods inherited from GameController
//

bool MainGameController::host(const wxString& level)
{
	mGameStateController = new ServerStartingGameStateController(level);

	return true;
}

bool MainGameController::join(const wxString& host, int port)
{
	mGameStateController = new ClientStartingGameStateController(host, port);

	return true;
}

void MainGameController::configurationChange()
{
	// Configuration can be changed only during Idle state. Creating a new IdleStateController
	// will result in repainting the logo with the new configurations
	this->changeState(new IdleGameStateController());
}

void MainGameController::kickOffClient()
{
	SmartPointer<NetworkEventData> data = new NetworkEventData();
	wxSocketBase* clientSocket = wxGetApp().getClientSocket();

	wxASSERT_MSG(wxGetApp().getServerSocket() != NULL, wxT("Kick off can be used only on server side!"));
	wxASSERT_MSG(clientSocket != NULL, wxT("No client to kock off!"));
	data->setDataType(NetworkEventData::KICK_OFF);
	// No error handling since we are going to close the connection anyway
	data->write(clientSocket);
	clientSocket->Destroy();
	clientSocket = NULL;
	wxGetApp().setClientSocket(NULL);
	// Change back to Server starting state to be able to handle new incoming connections
	this->changeState(new ServerStartingGameStateController(wxGetApp().getActualLevel()));
}

void MainGameController::finish(IGameController::FinishReason finishReason)
{
	switch(finishReason)
	{
		case IGameController::INVALID:
			wxASSERT_MSG(false, wxT("INVALID finish reason received. It could not happen!"));
			break;
		case IGameController::USER_EXIT:
			this->changeState(new IdleGameStateController());
			break;
		case IGameController::RESTART_FROM_USER:
			this->changeState(new GameStartedGameStateController(true));
			break;
		case IGameController::RESTART_FROM_REMOTE_SIDE:
			this->changeState(new GameStartedGameStateController(false));
			break;
		case IGameController::CRASHED:
			// In this case the mGameStateController must be a GameStartedGameStateController
			if(true == static_cast<GameStartedGameStateController*>(mGameStateController.get())->isLocalTurn())
				wxGetApp().getMainFrame()->showMessageDialog(wxT("You lost!"), MainFrame::GAME_FINISH);
			else
				wxGetApp().getMainFrame()->showMessageDialog(wxT("You won!"), MainFrame::GAME_FINISH);
			this->changeState(new GameFinishedGameStateController());
			break;
		case IGameController::FINISHED:
			// In this case the mGameStateController must be a GameStartedGameStateController
			if(true == static_cast<GameStartedGameStateController*>(mGameStateController.get())->isLocalTurn())
				wxGetApp().getMainFrame()->showMessageDialog(wxT("You won!"), MainFrame::GAME_FINISH);
			else
				wxGetApp().getMainFrame()->showMessageDialog(wxT("You lost!"), MainFrame::GAME_FINISH);
			this->changeState(new GameFinishedGameStateController());
			break;
		default:
			wxASSERT_MSG(false, wxT("Unknown finish reason received. It could not happen!"));
			break;
	}
}

void MainGameController::changeState(IGameStateController* gameStateController)
{
	WxUtils::TaskScheduler::schedule(new ChangeStateTask(this, gameStateController));
}

/**
 * Protected methods
 */

void MainGameController::handleSocketEvent(wxSocketEvent& socketEvent)
{
	switch(socketEvent.GetSocketEvent())
	{
		case wxSOCKET_INPUT:
			mGameStateController->handleSocketInput(socketEvent);
			break;
		case wxSOCKET_OUTPUT:
			mGameStateController->handleSocketOutput(socketEvent);
			break;
		case wxSOCKET_CONNECTION:
			mGameStateController->handleSocketConnection(socketEvent);
			break;
		case wxSOCKET_LOST:
			mGameStateController->handleSocketLost(socketEvent);
			break;
	}
}
